﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using iNet.Tasks;

namespace iNet.IO
{
	/// <summary>
	/// 檔案複製工作。
	/// </summary>
	public class FileCopyTask : Task
	{
		#region 欄位
		int _BufferSize = 4096;
		bool _DeleteSourceFile;
		string _DestinationFileName;
		string _SourceFileName;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 FileCopyTask 執行個體。
		/// </summary>
		public FileCopyTask()
		{ }
		/// <summary>
		/// 初始化新的 FileCopyTask 執行個體。
		/// </summary>
		/// <param name="srcFileName">來源檔案路徑。</param>
		/// <param name="destFileName">目標檔案路徑。</param>
		/// <param name="deleteSrcFile">複製完成後是否刪除來源檔案，預設值為 False。</param>
		public FileCopyTask(string srcFileName, string destFileName, bool deleteSrcFile = false)
		{
			_SourceFileName = srcFileName;
			_DestinationFileName = destFileName;
			_DeleteSourceFile = deleteSrcFile;
		}
		#endregion
		#region BufferSize
		/// <summary>
		/// 取得或設定複製資料時所使用的緩衝區位元組大小，預設值為 4096。
		/// </summary>
		public int BufferSize
		{
			get
			{
				return _BufferSize;
			}
			set
			{
				//確認參數
				if (value <= 0)
					throw new ArgumentOutOfRangeException();

				//設定參數
				this.SetInitializingParameter<int>(ref _BufferSize, value);
			}
		}
		#endregion
		#region DeleteSourceFile
		/// <summary>
		/// 取得或設定複製完成後是否要刪除來源檔案，預設值為 False。
		/// </summary>
		public bool DeleteSourceFile
		{
			get
			{
				return _DeleteSourceFile;
			}
			set
			{
				this.SetInitializingParameter<bool>(ref _DeleteSourceFile, value);
			}
		}
		#endregion
		#region DestinationFileName
		/// <summary>
		/// 取得或設定目標檔案名稱。
		/// </summary>
		public string DestinationFileName
		{
			get
			{
				return _DestinationFileName;
			}
			set
			{
				//確認參數
				if (value != null && !FileUtility.IsValidPath(value))
					throw new ArgumentException();

				//設定參數
				this.SetInitializingParameter<string>(ref _DestinationFileName, value);
			}
		}
		#endregion
		#region Execute
		protected override bool Execute(TaskVersion version)
		{
			//取得初始化參數
			int bufferSize;
			bool deleteSrcFile;
			string srcFileName, destFileName;
			if (!this.ReadValue<int>(version, ref _BufferSize, out bufferSize) ||
				!this.ReadValue<bool>(version, ref _DeleteSourceFile, out deleteSrcFile) ||
				!this.ReadValue<string>(version, ref _SourceFileName, out srcFileName) ||
				!this.ReadValue<string>(version, ref _DestinationFileName, out destFileName))
				return true;

			//確認參數
			if (PathComparer.Default.Equals(srcFileName, destFileName))
				return false;

			//直接移動檔案
			if (_DeleteSourceFile && PathComparer.Default.Equals(Path.GetPathRoot(srcFileName), Path.GetPathRoot(destFileName)))
			{
				try
				{
					File.Move(srcFileName, destFileName);
					return true;
				}
				catch (IOException ex)
				{ }
			}

			//開啟來源檔案
			FileStream srcStream;
			if (!FileUtility.TryOpenFile(srcFileName, FileMode.Open, FileAccess.Read, 3000, out srcStream))
				return false;

			//開啟目標檔案
			FileStream destStream;
			if (!FileUtility.TryOpenFile(destFileName, FileMode.Create, FileAccess.Write, 3000, out destStream))
			{
				srcStream.Close();
				return false;
			}

			//複製檔案
			try
			{
				//建立資料流複製工作
				StreamCopyTask streamCopyTask = new StreamCopyTask(srcStream, destStream);
				streamCopyTask.BufferSize = bufferSize;

				//複製檔案資料
				if (this.ExecuteChildTask(version, streamCopyTask, false) == TaskState.Error)
					return false;
			}
			finally
			{
				//關閉資料流
				destStream.Close();
				srcStream.Close();
			}

			//中斷確認
			if (this.IsCanceling)
				return true;

			//刪除來源檔案
			if (deleteSrcFile)
			{
				try
				{
					File.Delete(srcFileName);
				}
				catch
				{ }
			}

			//完成
			return true;
		}
		#endregion
		#region OnChildTaskProgressChanged
		protected override void OnChildTaskProgressChanged(TaskVersion version, Task childTask, TaskProgressChangedEventArgs e)
		{
			//回報進度
			this.ReportProgress(version, e.Progress);

			//呼叫基底
			base.OnChildTaskProgressChanged(version, childTask, e);
		}
		#endregion
		#region SourceFileName
		/// <summary>
		/// 取得或設定來源檔案名稱。
		/// </summary>
		public string SourceFileName
		{
			get
			{
				return _SourceFileName;
			}
			set
			{
				//確認參數
				if (value != null && !FileUtility.IsValidPath(value))
					throw new ArgumentException();

				//設定參數
				this.SetInitializingParameter<string>(ref _SourceFileName, value);
			}
		}
		#endregion
	}
}
